<?php
namespace zake\foundation\reactor\driver;

use zake\foundation\able\stream\DuplexDriverAble;
use zake\foundation\able\stream\ReadAble;
use zake\foundation\able\stream\ReadBufferAble;
use zake\foundation\able\stream\WriteAble;
use zake\foundation\able\stream\WriteBufferAble;
use zake\foundation\Process;
use zake\foundation\stream\BufferRwStream;
use zake\foundation\stream\ReadStream;
use zake\foundation\stream\WriteStream;
use zake\server\segment\Segment;

/**
 * Class Socket
 * @package zake\foundation\channel
 *
 * 套接字流：通信方式为全双工，FIFO模式
 *
 * 主要用途：主进程和子进程之间的全双工通信，socket支持 读写 操作
 *
 * @author liu.bin 2020-03-31 11:21
 */
class SocketPairChannelAdapt implements DuplexDriverAble
{
    /**
     * 当创建时进程的pid.一般指父进程
     * @var int
     */
    private $pid = 0;

    /**
     * @var array|bool
     */
    private $sockets = [];

    /**
     * 读
     * @var null|ReadBufferAble|ReadAble
     */
    private $readStream = null;

    /**
     * 写
     * @var null|WriteAble|WriteBufferAble
     */
    private $writeStream = null;


    /**
     * 构造器，在父进程中执行
     *
     * @param int $masterPid 父进程pid
     * @return DuplexDriverAble
     *
     * @author liu.bin 2020-03-30 15:27
     */
    public static function create()
    {
        $self = new static();
        return $self;
    }


    /**
     * 构造器
     *
     * SocketPair constructor.
     */
    public function __construct()
    {
        $this->sockets      = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
        $this->pid          = Process::pid();
    }


    /**
     * 初始化
     * @param int $pid
     *
     * @author liu.bin 2020-04-12 00:22
     */
    public function init($pid)
    {
        if($pid === $this->pid) {
            // (父)
            $resource = $this->sockets[0];
            fclose($this->sockets[1]);
        }else{
            //(子)
            $resource = $this->sockets[1];
            fclose($this->sockets[0]);
        }
        $rw = BufferRwStream::create($resource);
        $rw->setProtocol(Segment::singleton());
        $this->readStream = $this->writeStream = $rw;
    }


    /**
     * 获取读资源
     * @return ReadStream|ReadAble
     * @author liu.bin 2020-03-30 15:19
     */
    public function getReadStream()
    {
        return $this->readStream;
    }

    /**
     * 获取写资源
     * @return WriteStream|WriteAble
     * @author liu.bin 2020-03-31 15:58
     */
    public function getWriteStream()
    {
        return $this->writeStream;
    }
}